package com.luxsoft.siipap.em.replica.importadores.cxc;

import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.text.MessageFormat;
import java.util.List;

import org.apache.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SqlParameterValue;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.util.Assert;

import com.luxsoft.siipap.cxc.model.NotaDeCargo;
import com.luxsoft.siipap.cxc.model.NotaDeCargoDet;
import com.luxsoft.siipap.cxc.model.OrigenDeOperacion;
import com.luxsoft.siipap.em.replica.importadores.ImportadorSupport;
import com.luxsoft.siipap.em.replica.importadores.ventas.ImportadorDeVentas;
import com.luxsoft.siipap.model.CantidadMonetaria;
import com.luxsoft.siipap.model.Periodo;
import com.luxsoft.siipap.model.core.Cliente;
import com.luxsoft.siipap.service.ServiceLocator2;
import com.luxsoft.siipap.util.ValidationUtils;
import com.luxsoft.siipap.ventas.model.Venta;

/**
 * Importa las notas de cargo
 * 
 * @author Ruben Cancino Ramos
 *
 */
public class ImportadorDeNotasDeCargo {
	
	private int total;
	
	private int current;
	
	private Logger logger=Logger.getLogger(getClass());
	
	public ImportadorDeNotasDeCargo(){
	}
	
	protected void setProgress(int progress){
		logger.info("Progreso: "+progress);
	}
	
	protected void updateCurrent(){
		current++;		
		if(total!=0){
			int progress=current*100/this.total;			
			setProgress(progress);
		}
	}
	
	/**
	 * Importa o actualiza una nota en el nuevo sistema a partir
	 * del id en siipapwin
	 * 
	 * @param id
	 * @return
	 */
	public NotaDeCargo importar(Long id){
		String sql="SELECT * FROM V_CARGOS WHERE NOTA_ID=?";
		List<NotaDeCargo> res=getOrigenTemplate().query(sql, new Object[]{id}, new CargoMapper());		
		if(res.isEmpty()){
			logger.info("No econtro la nota de cargo en siipapwin Nota_ID="+id);
			return null;
		}
		NotaDeCargo cargo= res.get(0);
		try {
			insertarPartidas(cargo);
			return persistir(cargo);
		} catch (Exception e) {
			logger.error(e);
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * Importa todas las notas de un periodo para el tipo indicado
	 * 
	 * @param periodo
	 * 
	 */
	public void importar(final Periodo periodo){
		
		String sql="SELECT * FROM V_CARGOS  A WHERE A.FECHA BETWEEN ? AND ? AND TIPO in(\'M\',\'Q\')";
		Object[] params=new Object[]{
			new SqlParameterValue(Types.DATE,periodo.getFechaInicial())	
			,new SqlParameterValue(Types.DATE,periodo.getFechaFinal())
		};
		int tot=getOrigenTemplate().queryForInt("SELECT count(*) FROM V_CARGOS  A WHERE A.FECHA BETWEEN ? AND ?",params);
		logger.info("Total de registros a importar: "+tot );
		setTotal(tot);
		logger.info(MessageFormat.format("Mapeando para el periodo {0}",periodo));
		List<NotaDeCargo> cargos=getOrigenTemplate().query(sql, params,new CargoMapper());
		for (NotaDeCargo cargo : cargos) {
			try {
				insertarPartidas(cargo);				
				cargo=persistir(cargo);
				updateCurrent();
			} catch (Exception e) {
				e.printStackTrace();
				logger.error(e);
			}
			 	
		}
	}
	
	
	
	protected NotaDeCargo persistir(final NotaDeCargo cargo){
		
		NotaDeCargo target=buscarCargoPorSiipapId(cargo.getSiipapWinId());
		if(target==null){			
			target=cargo;
		}
		else{
			//copiar propiedades necesarias
			logger.info("Persistiendo nota existente: "+target.getSiipapWinId());
			target.getConceptos().clear();
			BeanUtils.copyProperties(cargo, target,new String[]{"id","version","conceptos"});			
			for(NotaDeCargoDet det:cargo.getConceptos()){
				target.agregarConcepto(det);				
			}
			
		}
		for(NotaDeCargoDet d:target.getConceptos()){
			target.agregarConcepto(d);
			d.setNotaDeCargo(target);
		}
		if(!ValidationUtils.isValid(target)){
			ValidationUtils.debugValidation(target);
		}
		//NotaDeCargo res= (NotaDeCargo)
		getHibernate().saveOrUpdate(target);
		//getHibernate().merge(target);
		
		return target;
	}
	
	
	
	private void insertarPartidas(final NotaDeCargo cargo){
		//String sql="select b.FECHA ,a.* from SW_NOTASDET a left join SW_NOTAS b on(a.NOTA_ID=b.NOTA_ID) where a.nota_id=? order by a.NOTADET_ID ASC";
		String sql="SELECT * FROM SW_NOTASDET WHERE NOTA_ID=?";		
		Object[] args=new Object[]{cargo.getSiipapWinId()};
		List<NotaDeCargoDet> partidas=getOrigenTemplate().query(sql, args, new CargoDetMapper());
		for (NotaDeCargoDet det : partidas) {
			if(det.getVenta()!=null)
				cargo.agregarConcepto(det);
		}
	}
	
	
	public JdbcTemplate getOrigenTemplate(){
		return ServiceLocator2.getAnalisisJdbcTemplate();
	}

	public int getTotal() {
		return total;
	}

	public void setTotal(int total) {
		this.total = total;
	}
	
	private class CargoMapper implements RowMapper{

		public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
			NotaDeCargo cargo=new NotaDeCargo();
			cargo.setOrigen(OrigenDeOperacion.valueOf(rs.getString("ORIGEN")));
			String clave=rs.getString("CLAVE");			
			Cliente c=ImportadorSupport.getInstance().buscarCliente(clave);
			if(c==null)
				c=new Cliente(clave,clave);
			cargo.setCliente(c);
			cargo.setDocumento(rs.getLong("NUMERO"));
			cargo.setFecha(rs.getDate("FECHA"));
			cargo.setImporte(rs.getBigDecimal("IMPORTE"));
			cargo.setImpuesto(cargo.getImporte().multiply(BigDecimal.valueOf(.15)));
			cargo.setTotal(rs.getBigDecimal("TOTAL"));
			cargo.setComentario(rs.getString("COMENTARIO"));
			cargo.setImpreso(rs.getDate("IMPRESO"));
			cargo.setSaldo(rs.getBigDecimal("SALDO"));
			cargo.setSiipapWinId(rs.getLong("NOTA_ID"));
			cargo.setSucursal(ImportadorSupport.getInstance().buscarSucursal(new Integer(1)));
			return cargo;
		}
		
	}
	
	private class CargoDetMapper implements RowMapper{
		public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
			NotaDeCargoDet det=new NotaDeCargoDet();
			det.setComentario(rs.getString("COMENTARIO"));
			CantidadMonetaria importe=CantidadMonetaria.pesos(rs.getBigDecimal("IMPORTE").doubleValue());
			importe=importe.divide(1.15);
			det.setImporte(importe.amount());
			det.setSiipapWinId(rs.getLong("NOTADET_ID"));
			Assert.notNull(det.getSiipapWinId(),"Detalle de cargo sin venta_id NOTADET_ID="+det.getSiipapWinId());			
			Long ventaId=rs.getLong("VENTA_ID");
			if(ventaId!=0){			
				Venta v=buscarVenta(ventaId);
				det.setVenta(v);
			}
			return det;
		}
		
	}
	
	
	
	public HibernateTemplate getHibernate(){
		return ServiceLocator2.getHibernateTemplate();
	}
	
	
	private NotaDeCargo buscarCargoPorSiipapId(Long siipapWinid){		
		List<NotaDeCargo> data=getHibernate().find("from NotaDeCargo c left join fetch c.conceptos cc where c.siipapWinId=?", siipapWinid);
		if(!data.isEmpty()){			
			return data.get(0);
		}
		return null;
	}
	
	
	private Venta buscarVenta(Long id){		
		List<Venta> data=getHibernate().find("from Venta c  where c.siipapWinId=?", id);
		if(data.isEmpty()){
			
			//La venta posiblemente no esta importada
			Venta venta=getImportadorDeVentas().importar(id);
			Assert.isTrue(venta!=null,"No se encontro ni se pudo importar la venta:"+id);
			return venta;
		}else{
			logger.info("Venta encontrada en MySQL");
			return data.get(0);
		}
	}
	
	private ImportadorDeVentas importadorDeVentas;
	
	private ImportadorDeVentas getImportadorDeVentas(){
		if(importadorDeVentas==null){
			importadorDeVentas=new ImportadorDeVentas();
		}
		return importadorDeVentas;
	}
	
	private static ImportadorDeNotasDeCargo INSTANCE;
	
	public static ImportadorDeNotasDeCargo instance(){
		if(INSTANCE==null){
			INSTANCE=new ImportadorDeNotasDeCargo();
		}
		return INSTANCE;
	}

	public static void main(String[] args) {
		ImportadorDeNotasDeCargo imp=instance();
		//imp.importar(Periodo.getPeriodoEnUnMes(0,2008));
		imp.importar(new Periodo("01/02/2008","31/12/2008"));
		//imp.importar(108283L);
		//imp.importar(114468L);
		//
		//imp.importar(123337L);
	}
}
